package ru.ifmo.network.skype;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import ru.ifmo.network.skype.audio.Config;
import ru.ifmo.network.skype.audio.receive.Player;
import ru.ifmo.network.skype.audio.send.AudioGrabber;
import ru.ifmo.network.skype.network.*;
import ru.ifmo.network.skype.view.ConsoleUserListHandler;
import ru.ifmo.network.skype.view.swing.GUI;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.LineUnavailableException;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * @author avhaliullin
 */
public class Launcher {
    public void run() throws LineUnavailableException, IOException {
        PatternLayout layout = new PatternLayout();
        layout.setConversionPattern("[%d] %-5p [%t] %m%n");
        Logger.getRootLogger().addAppender(new ConsoleAppender(layout));
        Config config = new Config(new AudioFormat(8000, 16, 1, true, false), 512, 33500, 33501);
        final int rndNum = new Random().nextInt();
        GroupsController groupsController = new GroupsController(new File("GROUPS"));
        SecureConnectionManager connectionManager = new RSAConnection();// new SimpleConnection();
        final String userName = JOptionPane.showInputDialog("Enter your nickname:", "username_" + rndNum);
        TCPServer tcpServer = new TCPServer(new UserDataProvider() {
            @Override
            public UserData getUserData() {
                return new UserData(null, userName);
            }
        }, connectionManager,
                groupsController, config.getTcpPort()
        );

        TCPClient tcpClient = new TCPClient(config.getTcpPort(), connectionManager);

        UserListController userListController = new UserListController(tcpClient);
        Player player = new Player(config);

        ReceiversGenerator receiversGenerator = new ReceiversGenerator(player);
        List<MessageHandler> handlers = new ArrayList<>();
        handlers.add(groupsController.getIncomeMessageHandler());
        handlers.add(userListController);

        final UDPMessageSender sender = new UDPMessageSender(config.getUdpPort());
        UDPMessageReceiver udpReceiver = new UDPMessageReceiver(config.getBufferSize(), handlers, config.getUdpPort());
        ConsoleUserListHandler consoleUserListHandler = new ConsoleUserListHandler();
        AudioGrabber audioGrabber = new AudioGrabber(groupsController.getOutcomeMessageHandler(), config);
        groupsController.setMessageHandler(receiversGenerator);
        groupsController.setSender(sender);

        userListController.addUserListHandler(receiversGenerator);
        userListController.addUserListHandler(consoleUserListHandler);

        GUI gui = new GUI(receiversGenerator, groupsController, tcpClient);
        userListController.addUserListHandler(gui);
        groupsController.addListener(gui);
        gui.setVisible(true);

        new Thread(tcpServer).start();
        new Thread(udpReceiver).start();
        audioGrabber.start();
        player.start();

        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                sender.handleGoodbye(null);
            }
        }));
    }

    public static void main(String[] args) throws LineUnavailableException, IOException {
        new Launcher().run();
    }
}
